Работа с типами BOOLEAN и GUID в Firebird и InterBase
Суть проблемы
- Тип GUID на текущий момент не поддерживается ни одним сервером Firebird и InterBase, но нередко используется различными клиентами (к примеру, в ADO Entity Framework).
- Тип Boolean поддерживается в InterBase начиная с 7-й версии и в Firebird начиная с 3-й версии.
В IBProvider поддержка типов Guid и Boolean была реализована на уровне драйвера, и теперь вы можете свободно использовать эти типы в своих приложениях независимо от версии сервера Firebird и InterBase.
Данные хранятся в типах, которые поддерживаются сервером. IBProvider просматривает домены данных и если обнаруживается домен, подходящий по маске, он выставляет колонке соответствующий тип Boolean или Guid.
Домены должны удовлетворять следующим условиям:
- для типа BOOLEAN домен базируется на типе SMALLINT.
- для типа GUID домен базируется на типе CHAR(16) с кодовой страницей OCTETS.
Свойства для включения эмуляции типов
Для того чтобы указать провайдеру какие данные следует интерпретировать как Boolean или Guid, в IBProvider добавлены два новых свойства инициализации: user_type_boolean, user_type_guid. В них определяется маска домена, который представляет эмулируемый тип. В маске поддерживаются символы «*» и «?». Маска чувствительна к регистру.
При несоблюдении этих условий, провайдер игнорирует имя домена и не пытается выполнять подмену типа.
Эмуляция работает для:
- Колонок с простым типом;
- Колонок с массивами;
- OUT-параметров с простым типом;
- OUT-параметров с массивами;
- IN-параметров с массивами.
Ограничения эмуляции типов
Из-за ограничений ISC API (IB/FB), при использовании простых типов для входящих параметров команд, необходимо явно указывать тип параметра. Для колонок с массивами поддерживается автоматическое формирование описания параметра.
Эмуляция типов в метаданных
Эмуляция типов распространяется и на схемы метаданных. Провайдер обеспечивает согласованность типов, которые читаются при выполнении запросов и типов, которые отображаются в схемах COLUMNS, PROCEDURE_PARAMETERS, PROCEDURE_COLUMNS.
Рабочий пример
Для демонстрации работы нам понадобится:
- IBProvider версии не ниже 3.0.0.7412.
- Любой сервер Firebird и InterBase.
Для начала создадим тестовую таблицу и домены, в которых будут храниться данные эмулируемых типов.
CREATE DOMAIN D_BOOL_D1 AS SMALLINT; CREATE DOMAIN D_GUID AS CHAR(16) CHARACTER SET OCTETS; CREATE TABLE TYPE_EMULATOR ( IDENTITY D_GUID, RESIDENT D_BOOL_D1 NOT NULL, FULLNAME VARCHAR(100));
Для того чтобы провайдер включил эмуляцию типов, необходимо в строке подключения задать маску, по которой будут отбираться домены:
user_type_boolean= D_BOOL_*;user_type_guid= D_GUID;
Далее пример кода на Visual C#, демонстрирующего использование эмулятора типов:
[Test] public void ComlexEmulatorTest() { // retrive standard connection string parameters from config OleDbConnectionStringBuilder sb = ConnectionProvider.GetConnectionStringBuilderFromUDL(); // add 2 masks for domains sb.Add("user_type_boolean", "D_BOOL*"); sb.Add("user_type_guid", "D_GUID*"); // disable resourse pooling because DROP operators are used sb.OleDbServices = OleDbServicesValues.EnableAll & ~OleDbServicesValues.ResourcePooling; using (OleDbConnection cn = new OleDbConnection(sb.ToString())) { cn.Open(); // inserting... OleDbTransaction tran = cn.BeginTransaction(IsolationLevel.RepeatableRead); OleDbCommand cmd = new OleDbCommand( "insert into type_emulator (identity, resident, fullname) values (?,?,?) ", cn, tran); Guid guid = Guid.NewGuid(); cmd.Parameters.Add("identity", OleDbType.Guid).Value = guid; cmd.Parameters.Add("resident", OleDbType.Boolean).Value = true; cmd.Parameters.AddWithValue("fullname", "Resident of Russian Federation"); Assert.AreEqual(cmd.ExecuteNonQuery(), 1); tran.Commit(); // selecting and validating tran = cn.BeginTransaction(IsolationLevel.RepeatableRead); cmd = new OleDbCommand("select * from type_emulator", cn, tran); using (OleDbDataReader rdr = cmd.ExecuteReader()) { if (rdr.Read()) { Console.WriteLine("Identity: {0} [type: {1}]", rdr["identity"], rdr["identity"].GetType().Name); Console.WriteLine("Resident: {0} [type: {1}]", rdr["resident"], rdr["resident"].GetType().Name); Console.WriteLine("Fullname: {0} [type: {1}]", rdr["fullname"], rdr["fullname"].GetType().Name); // check values Assert.AreEqual(guid, rdr["identity"]); Assert.AreEqual(rdr["resident"], true); } else Assert.Fail("Row was not inserted"); } tran.Commit(); } // Dispose cn.close }
Если свойства user_type_boolean и user_type_guid установлены правильно и версия IBProvider Professional не ниже 3.0.0.7412, в консоли будет отображен следующий текст:
identity: 6ef41c55-03ff-4941-9382-290813ad46c2 [type: Guid] Resident: True [type: Boolean] Fullname: Resident of Russian Federation [type: String]
Обратите внимание на то, что значения и типы в ADO .Net определены правильно в соответствии с заданными масками для доменов. В случае если маска домена не задана или используется другой провайдер после выполнения данного примера на экране отобразится текст:
identity: System.Byte[] [type: Byte[]] Resident: 1 [type: Int16] Fullname: Resident of Russian Federation [type: String]
То есть вместо типов Guid и Boolean будут отображаться стандартные типы.
Исходные тексты примеров для ADO .Net можно скачать здесь: Firebird ADO .Net Samples
Автор: Andrew A. Merkulov
|